package top.tenebrous.yzl.listener;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import top.tenebrous.yzl.entity.TestNoOffset;
import top.tenebrous.yzl.event.ArchiveResizeEvent;
import top.tenebrous.yzl.mapper.TestNoMapper;
import top.tenebrous.yzl.mapper.TestNoOffsetMapper;
import top.tenebrous.yzl.model.dto.TestNoDTO;
import top.tenebrous.yzl.utils.CommonUtils;
import top.tenebrous.yzl.utils.RedisLock;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

@Slf4j
@Component
public class ArchiveListener {

    @Resource
    private RedisTemplate<String, Long> redisTemplate;

    @Resource
    private TestNoMapper testNoMapper;

    @Resource
    private TestNoOffsetMapper testNoOffsetMapper;

    private final static Long DEFALUT_NUM = 100L;

    @Async("localBootAsyncExecutor")
    @EventListener
    @Transactional(rollbackFor = Exception.class)
    public void onApplicationEvent(ArchiveResizeEvent event) {
        String areaCode = event.getAreaCode();
        TestNoOffset offset = event.getOffset();
        log.info("接收到生成新位图事件 ====> 区域编码:[{}]  偏移量:{}", areaCode, JSON.toJSONString(offset));

        // 获取锁
        RedisLock redisLock = new RedisLock(redisTemplate, CommonUtils.generationRedisKey(areaCode, "RESIZE_LOCK"));
        try {
            if (!redisLock.tryLock(1000)) {
                log.info("获取锁失败....");
            } else {
                // 获取档案信息
                List<TestNoDTO> codes = testNoMapper.selectCodeByAreaCode(areaCode, DEFALUT_NUM, offset.getEndIncrVal() + 1);
                // 生成key 从上一个自增位 + 1  开始（包含）
                Long startIncr = offset.getEndIncrVal() + 1;
                Long endIncr = codes.get(codes.size() - 1).getIncrNum();

                String bitKey = CommonUtils.generationRedisKey(areaCode, startIncr, endIncr);
                if (Boolean.TRUE.equals(redisTemplate.hasKey(bitKey))) {
                    log.info("key:[{}] 已重设", bitKey);
                    return;
                }

                // 设置bit
                for (TestNoDTO testNo : codes) {
                    // 计算索引位
                    long lastEndVal = startIncr;   // 起始位置 = 上一个最大自增位 + 1
                    long index = testNo.getIncrNum() - lastEndVal;
                    redisTemplate.opsForValue().setBit(bitKey, index, true);
                    log.info("bit 重设code:[{}]  index:[{}]", JSON.toJSONString(testNo), index);
                }
                // 保存偏移
                offset.setNextActivityId(codes.get(codes.size() - 1).getId());
                offset.setNextStartIncrVal(startIncr);
                offset.setNextEndIncrVal(endIncr);
                offset.setUpdateDate(new Date());
                testNoOffsetMapper.updateById(offset);
                log.info("bit map resize success , key:[{}]  offset:{}", bitKey, JSON.toJSONString(offset));
            }
        } catch (Exception e) {
            log.error("rediskey 重设失败:{}", e);
        }finally {
            redisLock.unlock();
        }
    }

//    /**
//     * 编码启用监听
//     */
//    @Async("localBootAsyncExecutor")
//    @EventListener
//    @Transactional(rollbackFor = Exception.class)
//    public void onApplicationEvent(){}

}
